#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/mmc/dw_mmc.h>
#include <linux/clk.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/phy.h>
#include <linux/dma-mapping.h>
#include <linux/spi/eeprom.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/if_alg.h>
#include <linux/mmc/host.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/pmu.h>
#include <mach/io.h>
#include <mach/board_config.h>
#include <mach/pinctrl.h>
#include <mach/clock.h>
#include <mach/fh_uart_plat.h>
#include <mach/fh_mci_plat.h>
#include <mach/fh_mshc_plat.h>
#include <mach/fh_gmac_plat.h>
#include <mach/fh_gpio_plat.h>
#include <mach/mol_efuse_plat.h>
#include <mach/fh_dma_plat.h>
#include <mach/fh_spi_plat.h>
#include <mach/fh_i2s_plat.h>
#include <mach/fh_pwm_plat.h>
#include <mach/fh_wdt_plat.h>
#include <mach/fh_usb_plat.h>
#include <mach/fh_sadc_plat.h>
#include <mach/fh_rtc_plat.h>
#include <mach/platsmp.h>
#include "chip.h"
#include "../soc.h"
#include <linux/gpio.h>
#include <linux/irqchip/arm-gic.h>



#define CONFIG_GPIO_EMAC_0_PHY_RESET    (128)
#define CONFIG_GPIO_EMAC_1_PHY_RESET    (128)

struct uart_port fh_serial_ports[FH_UART_NUMBER];
static void *va_ephy;
static struct map_desc fh8898_io_desc[] = {
	{
		.virtual	= VA_CPU_SYS_APB_REG_BASE,
		.pfn		= __phys_to_pfn(CPU_SYS_APB_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_TOP_SYS_AHB_REG_BASE,
		.pfn		= __phys_to_pfn(TOP_SYS_AHB_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_TOP_SYS_APB_REG_BASE,
		.pfn		= __phys_to_pfn(TOP_SYS_APB_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_TOP_PRE_DIV_RF_REG_BASE,
		.pfn		= __phys_to_pfn(TOP_PRE_DIV_RF_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_CEN_GLB_APB_REG_BASE,
		.pfn		= __phys_to_pfn(CEN_GLB_APB_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_VDU_SYS_APB_REG_BASE,
		.pfn		= __phys_to_pfn(VDU_SYS_APB_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_DMC_SYS_APB_REG_BASE,
		.pfn		= __phys_to_pfn(DMC_SYS_APB_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_NNP_SYS_APB_REG_BASE,
		.pfn		= __phys_to_pfn(NNP_SYS_APB_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_USB3_PHY_REG_BASE,
		.pfn		= __phys_to_pfn(USB3_PHY_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_ISP_SYS_APB_REG_BASE,
		.pfn		= __phys_to_pfn(ISP_SYS_APB_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_VEU_SYS_AHB_REG_BASE,
		.pfn		= __phys_to_pfn(VEU_SYS_AHB_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_CEN_PIN_REG_BASE,
		.pfn		= __phys_to_pfn(CEN_PIN_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_VDU_SYS_PIN_REG_BASE,
		.pfn		= __phys_to_pfn(VDU_SYS_PIN_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_NNP_SYS_PIN_REG_BASE,
		.pfn		= __phys_to_pfn(NNP_SYS_PIN_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_ISP_SYS_PIN_REG_BASE,
		.pfn		= __phys_to_pfn(ISP_SYS_PIN_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_UART0_REG_BASE,
		.pfn		= __phys_to_pfn(UART0_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_UART1_REG_BASE,
		.pfn		= __phys_to_pfn(UART1_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_UART2_REG_BASE,
		.pfn		= __phys_to_pfn(UART2_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_UART3_REG_BASE,
		.pfn		= __phys_to_pfn(UART3_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
		.virtual	= VA_UART4_REG_BASE,
		.pfn		= __phys_to_pfn(UART4_REG_BASE),
		.length		= SZ_4K,
		.type		= MT_DEVICE,
	},
	{
	.virtual	= VA_UART5_REG_BASE,
	.pfn		= __phys_to_pfn(UART5_REG_BASE),
	.length		= SZ_4K,
	.type		= MT_DEVICE,
	},
	{
	.virtual	= VA_PTS_REG_BASE,
	.pfn		= __phys_to_pfn(PTS_REG_BASE),
	.length		= SZ_4K,
	.type		= MT_DEVICE,
	},
};

static struct resource fh_gpio0_resources[] = {
	{
		.start		= GPIO0_REG_BASE,
		.end		= GPIO0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO0_IRQ,
		.end		= GPIO0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio1_resources[] = {
	{
		.start		= GPIO1_REG_BASE,
		.end		= GPIO1_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO1_IRQ,
		.end		= GPIO1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio2_resources[] = {
	{
		.start		= GPIO2_REG_BASE,
		.end		= GPIO2_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO2_IRQ,
		.end		= GPIO2_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio3_resources[] = {
	{
		.start		= GPIO3_REG_BASE,
		.end		= GPIO3_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO3_IRQ,
		.end		= GPIO3_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gpio4_resources[] = {
	{
		.start		= GPIO4_REG_BASE,
		.end		= GPIO4_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= GPIO4_IRQ,
		.end		= GPIO4_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_uart0_resources[] = {
	{
		.start		= (UART0_REG_BASE),
		.end		= (UART0_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= UART0_IRQ,
		.end		= UART0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_uart1_resources[] = {
	{
		.start		= (UART1_REG_BASE),
		.end		= (UART1_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= UART1_IRQ,
		.end		= UART1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};
static struct resource fh_uart2_resources[] = {
	{
		.start		= (UART2_REG_BASE),
		.end		= (UART2_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= UART2_IRQ,
		.end		= UART2_IRQ,
		.flags		= IORESOURCE_IRQ,
	}
};

static struct resource fh_uart3_resources[] = {
	{
		.start		= (UART3_REG_BASE),
		.end		= (UART3_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= UART3_IRQ,
		.end		= UART3_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_uart4_resources[] = {
	{
		.start		= (UART4_REG_BASE),
		.end		= (UART4_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= UART4_IRQ,
		.end		= UART4_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_uart5_resources[] = {
	{
		.start		= (UART5_REG_BASE),
		.end		= (UART5_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= UART5_IRQ,
		.end		= UART5_IRQ,
		.flags		= IORESOURCE_IRQ,
	}
};

static struct resource fh_mc_hash_resources[] = {
	{
		.start		= (HASH_REG_BASE),
		.end		= (HASH_REG_BASE) + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= HASH_IRQ,
		.end		= HASH_IRQ,
		.flags		= IORESOURCE_IRQ,
	}
};



static struct resource fh_sfc_resources[] = {
	{
		.start		= SFC_REG_BASE,
		.end		= SFC_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SFC_IRQ,
		.end		= SFC_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_spi0_resources[] = {
	{
		.start		= SPI0_REG_BASE,
		.end		= SPI0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SPI0_IRQ,
		.end		= SPI0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_spi1_resources[] = {
	{
		.start		= SPI1_REG_BASE,
		.end		= SPI1_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SPI1_IRQ,
		.end		= SPI1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gmac_qos_0_resources[] = {
	{
		.start		= GMAC0_REG_BASE,
		.end		= GMAC0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= GMAC0_SBD_INTR_IRQ,
		.end		= GMAC0_SBD_INTR_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_gmac_qos_1_resources[] = {
	{
		.start          = GMAC1_REG_BASE,
		.end            = GMAC1_REG_BASE + SZ_16K - 1,
		.flags          = IORESOURCE_MEM,
	},

	{
		.start          = GMAC1_SBD_INTR_IRQ,
		.end            = GMAC1_SBD_INTR_IRQ,
		.flags          = IORESOURCE_IRQ,
	},
};


static struct resource fh_wdt0_resources[] = {
	{
		.start		= WDT0_REG_BASE,
		.end		= WDT0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= WDT0_IRQ,
		.end		= WDT0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_pwm_resources[] = {
	{
		.start		= PWM_REG_BASE,
		.end		= PWM_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= PWM_IRQ,
		.end		= PWM_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_i2c_resources_0[] = {
	{
		.start		= I2C0_REG_BASE,
		.end		= I2C0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= I2C0_IRQ,
		.end		= I2C0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_i2c_resources_1[] = {
	{
		.start		= I2C1_REG_BASE,
		.end		= I2C1_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= I2C1_IRQ,
		.end		= I2C1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_i2c_resources_2[] = {
	{
		.start		= I2C2_REG_BASE,
		.end		= I2C2_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= I2C2_IRQ,
		.end		= I2C2_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_i2c_resources_3[] = {
	{
		.start          = I2C3_REG_BASE,
		.end            = I2C3_REG_BASE + SZ_16K - 1,
		.flags          = IORESOURCE_MEM,
	},

	{
		.start          = I2C3_IRQ,
		.end            = I2C3_IRQ,
		.flags          = IORESOURCE_IRQ,
	},
};

static struct resource fh_i2c_resources_4[] = {
	{
		.start          = I2C4_REG_BASE,
		.end            = I2C4_REG_BASE + SZ_16K - 1,
		.flags          = IORESOURCE_MEM,
	},

	{
		.start          = I2C4_IRQ,
		.end            = I2C4_IRQ,
		.flags          = IORESOURCE_IRQ,
	},
};

static struct resource fh_i2c_resources_5[] = {
	{
		.start          = I2C5_REG_BASE,
		.end            = I2C5_REG_BASE + SZ_16K - 1,
		.flags          = IORESOURCE_MEM,
	},

	{
		.start          = I2C5_IRQ,
		.end            = I2C5_IRQ,
		.flags          = IORESOURCE_IRQ,
	},
};

static struct resource fh_rtc_resources[] = {
	{
		.start		= RTC_REG_BASE,
		.end		= RTC_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= RTC_IRQ,
		.end		= RTC_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

#ifdef CONFIG_FH_RSA
static struct resource fh_rsa_resources[] = {
	{
		.start		= RSA_REG_BASE,
		.end		= RSA_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},

	{
		.start		= RSA_IRQ,
		.end		= RSA_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};
#endif

#ifdef CONFIG_HW_RANDOM_FH
static struct resource fh_rng_resources[] = {
	{
		.start		= RNG_REG_BASE,
		.end		= RNG_REG_BASE + SZ_1M - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= RNG_IRQ,
		.end		= RNG_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};
#endif

static struct resource fh_usb0_resources[] = {
	{
		.start		= USB2_REG_BASE,
		.end		= USB2_REG_BASE + SZ_1M - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= USB2_IRQ,
		.end		= USB2_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_usb1_resources[] = {
	{
		.start		= USB3_REG_BASE,
		.end		= USB3_REG_BASE + SZ_1M - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= USB3_IRQ,
		.end		= USB3_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_sdc0_resources[] = {
	{
		.start		= SDIO0_REG_BASE,
		.end		= SDIO0_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SDIO0_IRQ,
		.end		= SDIO0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_sdc1_resources[] = {
	{
		.start		= SDIO1_REG_BASE,
		.end		= SDIO1_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SDIO1_IRQ,
		.end		= SDIO1_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_mshc_resources[] = {
	{
		.start		= EMMC_REG_BASE,
		.end		= EMMC_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= EMMC_PHY_REG_BASE,
		.end		= EMMC_PHY_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= EMMC_IRQ,
		.end		= EMMC_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
	{
		.start		= EMMC_PHY_IRQ,
		.end		= EMMC_PHY_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
	{
		.start		= EMMC_WAKEUP_IRQ,
		.end		= EMMC_WAKEUP_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct resource fh_sadc_resources[] = {
	{
		.start		= SADC_REG_BASE,
		.end		= SADC_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= SADC_IRQ,
		.end		= SADC_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

struct fh_sadc_platform_data fh_sadc_data = {
	.ref_vol = 1800,
	.active_bit = 0xfff,
};

static struct platform_device fh_sadc_device = {
	.name			= "fh_sadc",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_sadc_resources),
	.resource		= fh_sadc_resources,
	.dev			= {
	.platform_data = &fh_sadc_data,
	},
};

static struct fh_platform_uart fh_uart_platform_data[] = {
	{
		.mapbase	= UART0_REG_BASE,
		.fifo_size	= 16,
		.irq		= UART0_IRQ,
		.uartclk	= 24000000,
	},
	{
		.mapbase	= UART1_REG_BASE,
		.fifo_size	= 32,
		.irq		= UART1_IRQ,
		.uartclk	= 24000000,
	},
	{
		.mapbase	= UART2_REG_BASE,
		.fifo_size	= 32,
		.irq		= UART2_IRQ,
		.uartclk	= 24000000,
	},
	{
		.mapbase	= UART3_REG_BASE,
		.fifo_size	= 32,
		.irq		= UART3_IRQ,
		.uartclk	= 24000000,
	},
	{
		.mapbase	= UART4_REG_BASE,
		.fifo_size	= 32,
		.irq		= UART4_IRQ,
		.uartclk	= 24000000,
	},
	{
		.mapbase	= UART5_REG_BASE,
		.fifo_size	= 32,
		.irq		= UART5_IRQ,
		.uartclk	= 24000000,
	},
};



struct phy_reg_cfg phy_config_array[] = {
	{
		.id = FH_GMAC_PHY_RTL8201,
		.list = {
			{W_PHY, 0x1f, 0x7},
			{W_PHY, 0x10, 0x1ffc},
			{W_PHY, 0x1f, 0},
			{W_PHY, 0x0d, 0x07},
			{W_PHY, 0x0e, 0x3c},
			{W_PHY, 0x0d, 0x4007},
			{W_PHY, 0x0e, 0x0},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_IP101G,
		.list = {
			{W_PHY, 0x14, 0x10},
			{W_PHY, 0x10, 0x1006},
			{W_PHY, 0x14, 0x10},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_TI83848,
		.list = {
			{M_PHY, 0x11, 0x20, 0x20},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_DUMMY,
		.list = {
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_INTERNAL_V2,
		.list = {
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_MII,
	},
	{0},
};

void fh_external_phy_0_reset(void)
{
	int ret;
	int reset_pin = CONFIG_GPIO_EMAC_0_PHY_RESET;

	ret = gpio_request(reset_pin, "phy0reset-gpio");
	if (ret) {
		pr_err("%s: ERROR: request reset pin : %d failed\n",
		__func__, reset_pin);
		return;
	}

	gpio_direction_output(reset_pin, GPIOF_OUT_INIT_HIGH);
	usleep_range(150000, 200000);
	gpio_direction_output(reset_pin, GPIOF_OUT_INIT_LOW);
	/* actual is 20ms */
	usleep_range(10000, 20000);
	gpio_direction_output(reset_pin, GPIOF_OUT_INIT_HIGH);
	usleep_range(10000, 20000);

	gpio_free(reset_pin);
}

void fh_external_phy_1_reset(void)
{
	int ret;
	int reset_pin = CONFIG_GPIO_EMAC_1_PHY_RESET;

	ret = gpio_request(reset_pin, "phy1reset-gpio");
	if (ret) {
		pr_err("%s: ERROR: request reset pin : %d failed\n",
		__func__, reset_pin);
		return;
	}

	gpio_direction_output(reset_pin, GPIOF_OUT_INIT_HIGH);
	usleep_range(150000, 200000);
	gpio_direction_output(reset_pin, GPIOF_OUT_INIT_LOW);
	/* actual is 20ms */
	usleep_range(10000, 20000);
	gpio_direction_output(reset_pin, GPIOF_OUT_INIT_HIGH);
	usleep_range(10000, 20000);

	gpio_free(reset_pin);
}

static int phy_0_inf_set(unsigned int inf)
{

	if (inf == PHY_INTERFACE_MODE_RGMII) {
		pr_err("unsupport RGMII...\n");
		return -1;
	}

	if (inf == PHY_INTERFACE_MODE_RMII) {
		//rmii interface select, [15:13] b'100 == rmii
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0x8000, 0xe000);
	} else {
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0, 0xe000);
	}

	return 0;
}

static int phy_1_inf_set(unsigned int inf)
{

	if (inf == PHY_INTERFACE_MODE_RGMII) {
		pr_err("unsupport RGMII...\n");
		return -1;
	}

	if (inf == PHY_INTERFACE_MODE_RMII) {
		//rmii interface select, [18:16] b'100 == rmii
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0x40000, 0x70000);
	} else {
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0, 0x70000);
	}
	return 0;
}

static int eth_0_set_speed(unsigned int speed, void *pri)
{
	//pr_err("eth_0_set_speed is [%d]\n", speed);
	//soc just need to set mac control reg
	return 0;
}

static int eth_1_set_speed(unsigned int speed, void *pri)
{
	//pr_err("eth_1_set_speed is [%d]\n", speed);
	//soc just need to set mac control reg
	return 0;
}

static int phy_0_sel_func(unsigned int phy_sel)
{
	if (phy_sel == EXTERNAL_PHY) {
		//external phy sel
		//external phy enable
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		1, 0x3);
		//open external phy clk
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		1 << 20, 1 << 20);
	} else {
		//close external phy clk oe
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0 << 20, 1 << 20);
		//enable internal phy
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0, 0x3);
		//open internal phy clk
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x17c,
		1 << 20, 1 << 20);
		//ephy reset
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		1 << 4, 1 << 4);
		//maybe need delay?
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0, 1 << 4);
	}
	return 0;
}



static int phy_1_sel_func(unsigned int phy_sel)
{

	if (phy_sel == EXTERNAL_PHY) {
		//external phy sel
		//external phy enable
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		2 << 2, 0x3 << 2);
		//open external phy clk
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		1 << 19, 1 << 19);
	} else {
		//close external phy clk oe
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0 << 19, 1 << 19);
		//internal phy sel
		//enable internal phy
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0, 0x3 << 2);
		//open internal phy clk
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x17c,
		1 << 20, 1 << 20);
		//ephy reset
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		1 << 5, 1 << 5);
		//maybe need delay?
		fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
		0, 1 << 5);
	}
	return 0;
}

enum {
	CP_VAL_0,
	CP_VAL_1,
	VAL_100M_0,
	VAL_100M_1,
	VAL_10M_0,
	VAL_10M_1,
	TRAIN_MAX_SIZE,
};

static u32 train_100_array[] = {
	31, 30, 29, 28,
	27, 26, 25, 24,
	23, 22, 21, 20,
	19, 18, 17, 16,
	0,  1,  2,  3,
	4,  5,  6,  7,
	8,  9,  10, 11,
	12, 13, 14, 15,
};

static u32 train_10_array[] = {
	31, 30, 29, 28,
	27, 26, 25, 24,
	23, 22, 21, 20,
	19, 18, 17, 16,
	0,  1,  2,  3,
	4,  5,  6,  7,
	8,  9,  10, 11,
	12, 13, 14, 15,
};

static u32 train_cp_array[] = {
	0, 1, 2, 3,
};
#define REFIX_CP_TRAIN_DATA_OFFSET	    (0)
#define REFIX_100M_TRAIN_DATA_OFFSET    (0)
#define REFIX_10M_TRAIN_DATA_OFFSET	    (0)

struct s_train_val train_array[TRAIN_MAX_SIZE] = {

		[CP_VAL_0].name = "cp_val_0",
		[CP_VAL_0].src_add = REG_PMU_EPHY_PARAM,
		[CP_VAL_0].src_mask = 0xc0,
		[CP_VAL_0].src_vaild_index = 15,
		[CP_VAL_0].dst_add = 0x18,
		[CP_VAL_0].dst_vaild_index = 22,
		[CP_VAL_0].bind_train_array = train_cp_array,
		[CP_VAL_0].bind_train_size = ARRAY_SIZE(train_cp_array),
		[CP_VAL_0].usr_train_offset =
		REFIX_CP_TRAIN_DATA_OFFSET,

		[CP_VAL_1].name = "cp_val_1",
		[CP_VAL_1].src_add = REG_PMU_EPHY_PARAM,
		[CP_VAL_1].src_mask = 0xc0,
		[CP_VAL_1].src_vaild_index = 15,
		[CP_VAL_1].dst_add = 0xb7c,
		[CP_VAL_1].dst_vaild_index = 6,
		[CP_VAL_1].bind_train_array = train_cp_array,
		[CP_VAL_1].bind_train_size = ARRAY_SIZE(train_cp_array),
		[CP_VAL_1].usr_train_offset =
		REFIX_CP_TRAIN_DATA_OFFSET,

		[VAL_100M_0].name = "val_100M_0",
		[VAL_100M_0].src_add = REG_PMU_EPHY_PARAM,
		[VAL_100M_0].src_mask = 0x1f,
		[VAL_100M_0].src_vaild_index = 5,
		[VAL_100M_0].dst_add = 0x24,
		[VAL_100M_0].dst_vaild_index = 8,
		[VAL_100M_0].bind_train_array = train_100_array,
		[VAL_100M_0].bind_train_size = ARRAY_SIZE(train_100_array),
		[VAL_100M_0].usr_train_offset =
		REFIX_100M_TRAIN_DATA_OFFSET,

		[VAL_100M_1].name = "val_100M_1",
		[VAL_100M_1].src_add = REG_PMU_EPHY_PARAM,
		[VAL_100M_1].src_mask = 0x1f,
		[VAL_100M_1].src_vaild_index = 5,
		[VAL_100M_1].dst_add = 0x1308,
		[VAL_100M_1].dst_vaild_index = 8,
		[VAL_100M_1].bind_train_array = train_100_array,
		[VAL_100M_1].bind_train_size = ARRAY_SIZE(train_100_array),
		[VAL_100M_1].usr_train_offset =
		REFIX_100M_TRAIN_DATA_OFFSET,

		[VAL_10M_0].name = "val_10M_0",
		[VAL_10M_0].src_add = REG_PMU_EPHY_PARAM,
		[VAL_10M_0].src_mask = 0x1f00,
		[VAL_10M_0].src_vaild_index = 13,
		[VAL_10M_0].dst_add = 0x24,
		[VAL_10M_0].dst_vaild_index = 16,
		[VAL_10M_0].bind_train_array = train_10_array,
		[VAL_10M_0].bind_train_size = ARRAY_SIZE(train_10_array),
		[VAL_10M_0].usr_train_offset =
		REFIX_10M_TRAIN_DATA_OFFSET,

		[VAL_10M_1].name = "val_10M_1",
		[VAL_10M_1].src_add = REG_PMU_EPHY_PARAM,
		[VAL_10M_1].src_mask = 0x1f00,
		[VAL_10M_1].src_vaild_index = 13,
		[VAL_10M_1].dst_add = 0x1308,
		[VAL_10M_1].dst_vaild_index = 0,
		[VAL_10M_1].bind_train_array = train_10_array,
		[VAL_10M_1].bind_train_size = ARRAY_SIZE(train_10_array),
		[VAL_10M_1].usr_train_offset =
		REFIX_10M_TRAIN_DATA_OFFSET,
};

void dump_phy_train_val(struct s_train_val *p_train)
{
	pr_err("------------GAP_LINE---------------\n");
	pr_err("name            : %s\n", p_train->name);
	pr_err("src_add         : %08x\n", p_train->src_add);
	pr_err("src_mask        : %08x\n", p_train->src_mask);
	pr_err("src_vaild_index : %08x\n", p_train->src_vaild_index);
	pr_err("dst_add         : %08x\n", p_train->dst_add);
	pr_err("dst_vaild_index : %08x\n", p_train->dst_vaild_index);
	pr_err("usr_train_offset: %d\n", p_train->usr_train_offset);
}


void parse_train_data(struct s_train_val *p_train)
{
	unsigned long test_data;
	int i;
	u32 temp_data;
	u32 vaild_bit_pos;
	int max_offset, low_offset;
	u32 *array;
	u32 size;

	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}

	array = p_train->bind_train_array;
	size = p_train->bind_train_size;
	test_data = p_train->src_mask;
	vaild_bit_pos = find_first_bit(&test_data, 32);

	if ((!array) ||
	((p_train->src_mask >> vaild_bit_pos) != (size - 1))) {
		pr_err("para error..\n");
		return;
	}

	temp_data = fh_pmu_get_reg(p_train->src_add);
	if (temp_data & (1 << p_train->src_vaild_index)) {
		/*got vaild val*/
		temp_data &= p_train->src_mask;
		temp_data >>= vaild_bit_pos;
		pr_err("[%s] :: train val %d\n", p_train->name, temp_data);
		/*find index*/
		for (i = 0; i < size; i++) {
			if (temp_data == array[i]) {
				max_offset = (size - 1) - i;
				low_offset = 0 - i;
				break;
			}
		}

		if ((p_train->usr_train_offset < low_offset) ||
		(p_train->usr_train_offset > max_offset)) {
			pr_err("offset [%d] should limit in [%d , %d]\n",
			p_train->usr_train_offset, low_offset, max_offset);
			return;
		}
		//fix array idx..
		i += p_train->usr_train_offset;
		temp_data = array[i];
		/*pr_err("fix idx :: [%d] = %d\n", i, temp_data);*/
	} else {
		temp_data = 0;
		pr_err("[%s] :: use default train data %d\n",
		p_train->name, temp_data);
	}
	temp_data &= (p_train->src_mask >> vaild_bit_pos);
	SET_REG_M((u32)va_ephy + p_train->dst_add,
	temp_data << p_train->dst_vaild_index,
	(p_train->src_mask >> vaild_bit_pos) << p_train->dst_vaild_index);
}


static void fh_internal_phy_reset(void)
{
	int idx;

	/*just map once*/
	if (!va_ephy)
		va_ephy = ioremap(EPHY_REG_BASE, SZ_16K);

	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}

	pr_err("fh internal phy reset go...\n ");
	SET_REG_M((u32)va_ephy + 0, 0, 0x3<<7);
	SET_REG((u32)va_ephy + 0x28, 0x00247875);
	SET_REG((u32)va_ephy + 0x1274, 0x3c3);

	SET_REG_M((u32)va_ephy + 0x1370, 0x0, 1<<3);
	SET_REG((u32)va_ephy + 0x1274, 0x3c3);
	SET_REG((u32)va_ephy + 0x0b6C, 0xf04);
	SET_REG((u32)va_ephy + 0x1340, 0x0000);
	SET_REG((u32)va_ephy + 0x0bA8, 0x20);
	SET_REG((u32)va_ephy + 0x0018, 0x00c02800);
	SET_REG((u32)va_ephy + 0x001c, 0x00810000);
	SET_REG((u32)va_ephy + 0x0020, 0x0000340c);
	SET_REG((u32)va_ephy + 0x0024, 0x10131500);
	SET_REG((u32)va_ephy + 0x0028, 0x01402800);
	SET_REG((u32)va_ephy + 0x001c, 0xa1800000);
	SET_REG((u32)va_ephy + 0x0028, 0x00402800);
	SET_REG((u32)va_ephy + 0x0014, 0x06000000);
	SET_REG((u32)va_ephy + 0x0020, 0x2340c);
	SET_REG((u32)va_ephy + 0x000c, 0xba0edfff);
	SET_REG((u32)va_ephy + 0x0010, 0x7fcbf9de);
	SET_REG((u32)va_ephy + 0x0b98, 0xd150);
	SET_REG((u32)va_ephy + 0x1224, 0);
	SET_REG((u32)va_ephy + 0x12f0, 0);
	SET_REG((u32)va_ephy + 0x0bc0, 0x7de);
	SET_REG((u32)va_ephy + 0x0bc8, 0x09de);
	SET_REG((u32)va_ephy + 0x070c, 0x0401);
	SET_REG((u32)va_ephy + 0x0a84, 0x1d20);
	SET_REG((u32)va_ephy + 0x06d4, 0x3130);
	SET_REG((u32)va_ephy + 0x0a6c, 0x0818);
	SET_REG((u32)va_ephy + 0x0aec, 0x1000);
	SET_REG((u32)va_ephy + 0x0658, 0x1c00);
	SET_REG((u32)va_ephy + 0x07d4, 0x6900);
	SET_REG((u32)va_ephy + 0x06b8, 0x4);
	SET_REG((u32)va_ephy + 0x06E4, 0x04a0);
	SET_REG((u32)va_ephy + 0x0BBC, 0x1759);
	SET_REG((u32)va_ephy + 0x0bf8, 0x0100);
	SET_REG((u32)va_ephy + 0x0794, 0x9000);
	SET_REG((u32)va_ephy + 0x0788, 0xb);
	SET_REG((u32)va_ephy + 0x1378, 0x1820);
	SET_REG_M((u32)va_ephy + 0x0, 0x23<<24, 0xff<<24);
	SET_REG_M((u32)va_ephy + 0x4, 0x18, 0xff);
	SET_REG((u32)va_ephy + 0x0680, 0x0552);
	SET_REG((u32)va_ephy + 0x1274, 0);
	SET_REG((u32)va_ephy + 0x0b6C, 0x704);
	SET_REG((u32)va_ephy + 0x1340, 0);
	SET_REG((u32)va_ephy + 0x0ba8, 0);
	SET_REG((u32)va_ephy + 0x06c8, 0xc000);
	SET_REG((u32)va_ephy + 0x06e0, 0x8508);
	SET_REG((u32)va_ephy + 0x1360, 0x0137);

	SET_REG((u32)va_ephy + 0x076c, 0x0430);
	SET_REG((u32)va_ephy + 0x06b4, 0xff00);

	SET_REG_M((u32)va_ephy + 0x0778, 0x24 << 8, 0xff << 8);
	SET_REG_M((u32)va_ephy + 0x077c, 0x24, 0xff);

	for (idx = 0; idx < ARRAY_SIZE(train_array); idx++) {
		/*dump_phy_train_val(&train_array[idx]);*/
		parse_train_data(&train_array[idx]);
	}
}


static void fh_internal_phy_link_up_cb(void *pri)
{

	struct mii_bus *p_mii_bus;
	struct phy_device *phydev;

	p_mii_bus = (struct mii_bus *)pri;
	phydev = mdiobus_get_phy(p_mii_bus, 0);
	if (!phydev)
		return;

	if (!va_ephy) {
		pr_err("va_ephy is null\n");
		BUG_ON(1);
	}

	SET_REG((u32)va_ephy + 0x0b10, 0x5000);
	SET_REG((u32)va_ephy + 0x0b14, 0x8000);
	SET_REG((u32)va_ephy + 0x0b1c, 0x000e);
	SET_REG((u32)va_ephy + 0x0b20, 0x0004);
	SET_REG((u32)va_ephy + 0x0aec, 0x1800);
	SET_REG((u32)va_ephy + 0x0b10, 0x0000);
	SET_REG((u32)va_ephy + 0x0b14, 0x0000);

	if (phydev->speed == SPEED_10)
		SET_REG_M((u32)va_ephy + 0x7f8, 0x3<<8, 0x3<<8);

}

static void fh_internal_phy_link_down_cb(void *pri)
{
	if (!va_ephy) {
		pr_err("va_ephy is null\n");
		BUG_ON(1);
	}
}


static void fh_external_phy_link_up_cb(void *pri)
{
	struct mii_bus *p_mii_bus;
	struct phy_device *phydev;

	p_mii_bus = (struct mii_bus *)pri;
	phydev = mdiobus_get_phy(p_mii_bus, 0);
	if (!phydev)
		return;

	if (phydev->phy_id == FH_GMAC_PHY_RTL8201) {
		mdiobus_write(p_mii_bus, 0, 31, 7);
		mdiobus_write(p_mii_bus, 0, 19, 0xc00c);
		if (phydev->speed == SPEED_100)
			mdiobus_write(p_mii_bus, 0, 17, 0x28);
		else if (phydev->speed == SPEED_10)
			mdiobus_write(p_mii_bus, 0, 17, 0x18);

		mdiobus_write(p_mii_bus, 0, 31, 0);
	}
}

static void fh_external_phy_link_down_cb(void *pri)
{

}


static struct fh_gmac_platform_data fh_gmac0_plat_data = {
	.phy_sel = phy_0_sel_func,
	.inf_set = phy_0_inf_set,
	.gmac_reset = 0,
	.p_cfg_array = phy_config_array,
	.phy_info[0] = {
		.phy_sel = EXTERNAL_PHY,
		.phy_inf = PHY_INTERFACE_MODE_RMII,
		.phy_reset = fh_external_phy_0_reset,
		.ex_sync_mac_spd = eth_0_set_speed,
		.brd_link_up_cb = fh_external_phy_link_up_cb,
		.brd_link_down_cb = fh_external_phy_link_down_cb,
	},

};

static struct fh_gmac_platform_data fh_gmac1_plat_data = {
	.phy_sel = phy_1_sel_func,
	.inf_set = phy_1_inf_set,
	.gmac_reset = 0,
	.p_cfg_array = phy_config_array,

	.phy_info[0] = {
		.phy_sel = INTERNAL_PHY,
		.phy_inf = PHY_INTERFACE_MODE_MII,
		.phy_reset = fh_internal_phy_reset,
		.ex_sync_mac_spd = 0,
		.brd_link_up_cb = fh_internal_phy_link_up_cb,
		.brd_link_down_cb = fh_internal_phy_link_down_cb,
	},
	.phy_info[1] = {
		.phy_sel = EXTERNAL_PHY,
		.phy_inf = PHY_INTERFACE_MODE_RMII,
		.phy_reset = fh_external_phy_1_reset,
		.ex_sync_mac_spd = eth_1_set_speed,
		.brd_link_up_cb = fh_external_phy_link_up_cb,
		.brd_link_down_cb = fh_external_phy_link_down_cb,
	},
};


static struct platform_device fh_gmac_qos_0_device = {
	.name           = "fh_qos_gmac",
	.id             = 0,
	.num_resources  = ARRAY_SIZE(fh_gmac_qos_0_resources),
	.resource       = fh_gmac_qos_0_resources,
	.dev = {
		.coherent_dma_mask = DMA_BIT_MASK(32),
		.platform_data = &fh_gmac0_plat_data,
	},
};

static struct platform_device fh_gmac_qos_1_device = {
	.name           = "fh_qos_gmac",
	.id             = 1,
	.num_resources  = ARRAY_SIZE(fh_gmac_qos_1_resources),
	.resource       = fh_gmac_qos_1_resources,
	.dev = {
		.coherent_dma_mask = DMA_BIT_MASK(32),
		.platform_data = &fh_gmac1_plat_data,
	},
};

static struct fh_gpio_chip fh_gpio0_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO0",
		.base = 0,
		.ngpio = 32,
	},
};

static struct fh_gpio_chip fh_gpio1_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO1",
		.base = 32,
		.ngpio = 32,
	},
};

static struct fh_gpio_chip fh_gpio2_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO2",
		.base = 64,
		.ngpio = 32,
	},
};

static struct fh_gpio_chip fh_gpio3_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO3",
		.base = 96,
		.ngpio = 32,
	},
};

static struct fh_gpio_chip fh_gpio4_chip = {
	.chip = {
		.owner = THIS_MODULE,
		.label = "FH_GPIO4",
		.base = 128,
		.ngpio = 32,
	},
};


int fh_mci_sys_init(unsigned int slot_id, void *irq_handler_t, void *para)
	{
	unsigned int reg;

	if (slot_id == 1) {
		/*clk gate*/
		reg = readl(CK_CTRL0);
		reg |= (SDIO1_EN | SDIO1_DLLREF_EN);
		writel(reg, CK_CTRL0);

		reg = readl(CK_CTRL2);
		reg |= (AXI_SDIO1_EN);
		writel(reg, CK_CTRL2);


		/*sel clk 50M*/
		reg = readl(CK_CTRL0);
		reg &= (~SDIO1_CLK_SEL);
		reg |= 0x1 << 18;
		writel(reg, CK_CTRL0);
		/*config dll*/
		writel(0x104, SDIO1_CTRL0);
		writel(0x4204, SDIO1_DLLINCTRLREG_SPL);
		writel(0x5204, SDIO1_DLLINCTRLREG_SPL);
		writel(0x4204, SDIO1_DLLINCTRLREG_DRV);
		writel(0x5204, SDIO1_DLLINCTRLREG_DRV);
		do {
			reg = readl(SDIO1_DLLOUTREG_DRV);
		} while (!(reg & 0x01));

		do {
			readl(SDIO1_DLLOUTREG_SPL);
		} while (!(reg & 0x01));

		writel(0x20, SDIO1_DLLININFOREG_SPL);
		writel(0x7204, SDIO1_DLLINCTRLREG_SPL);
		writel(0x5204, SDIO1_DLLINCTRLREG_SPL);
		writel(0x7f, SDIO1_DLLININFOREG_DRV);
		writel(0x7204, SDIO1_DLLINCTRLREG_DRV);
		writel(0x5204, SDIO1_DLLINCTRLREG_DRV);
		writel(0xf24, SDIO1_CTRL0);

		/*rst sdio*/
		reg = readl(SOFT_RST0);
		reg |= SDIO1_SOFT_RST;
		udelay(1000);
		writel(reg, SOFT_RST0);
		reg &= (~SDIO1_SOFT_RST);
		udelay(1000);
		writel(reg, SOFT_RST0);
	} else {
		/*clk gate*/
		reg = readl(SDIO0_CLK_RST_CTRL);
		reg |= (SDIO0_EN | SDIO0_DLLREF_EN | AXI_SDIO0_EN);
		writel(0x2b, SDIO0_CLK_RST_CTRL);


		/*sel clk 50M*/
		reg = readl(SDIO0_CLK_RST_CTRL);
		reg &= (~SDIO0_CLK_SEL);
		reg |= 0x1 << 3;
		writel(reg, SDIO0_CLK_RST_CTRL);
		/*config dll*/

		writel(0x104, SDIO0_CTRL0);
		/*writel(0x30c, SDIO0_CTRL0);*/
		writel(0x4204, SDIO0_DLLINCTRLREG_SPL);
		writel(0x5204, SDIO0_DLLINCTRLREG_SPL);
		writel(0x4204, SDIO0_DLLINCTRLREG_DRV);
		writel(0x5204, SDIO0_DLLINCTRLREG_DRV);
		do {
			reg = readl(SDIO0_DLLOUTREG_DRV);
		} while (!(reg & 0x01));

		do {
			readl(SDIO0_DLLOUTREG_SPL);
		} while (!(reg & 0x01));

		writel(0x20, SDIO0_DLLININFOREG_SPL);
		writel(0x7204, SDIO0_DLLINCTRLREG_SPL);
		writel(0x5204, SDIO0_DLLINCTRLREG_SPL);
		writel(0x7f, SDIO0_DLLININFOREG_DRV);
		writel(0x7204, SDIO0_DLLINCTRLREG_DRV);
		writel(0x5204, SDIO0_DLLINCTRLREG_DRV);
		writel(0x924, SDIO0_CTRL0);
		/*writel(0xb2c, SDIO0_CTRL0);*/
		/*rst sdio*/
		reg = readl(SDIO0_CLK_RST_CTRL);
		reg |= SDIO0_SOFT_RST;
		udelay(1000);
		writel(reg, SDIO0_CLK_RST_CTRL);
		reg &= (~SDIO0_SOFT_RST);
		udelay(1000);
		writel(reg, SDIO0_CLK_RST_CTRL);
	}
	return 0;
}
struct fh_mci_board fh_mci_sd = {
	.num_slots = 1,
	.bus_hz = 50000000,
	.detect_delay_ms = 200,
	.caps = MMC_CAP_4_BIT_DATA,
	/*8:180  degree*/
	.drv_degree = 8,
	.sam_degree = 0,
	.init = fh_mci_sys_init,
	.rescan_max_num = 0,
};

struct platform_device fh_sd0_device = {
	.name			= "fh_mci",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_sdc0_resources),
	.resource		= fh_sdc0_resources,
	.dev			= {
	.coherent_dma_mask	= DMA_BIT_MASK(32),
	.platform_data = &fh_mci_sd,
	}
};
struct platform_device fh_sd1_device = {
	.name			= "fh_mci",
	.id			= 1,
	.num_resources		= ARRAY_SIZE(fh_sdc1_resources),
	.resource		= fh_sdc1_resources,
	.dev			= {
	.coherent_dma_mask	= DMA_BIT_MASK(32),
	.platform_data = &fh_mci_sd,
	}
};


struct mshc_lite_emmc_card_info emmc_card_array[] = {

	{
		.mmc_name = "016G30",
	},
	{
		.mmc_name = "BJTD4R",
	},
	{
		.mmc_name = "8GTF4R",
		#if (0)
		.flag = FORCE_USR_SETTING,
		hs200	:	.sup_mode = MSHC_MMC_MODE_HS200_1_8V
		hs400_classic	:	.sup_mode = MSHC_MMC_MODE_HS400_1_8V
		hs400_es	:	.sup_mode = MSHC_MMC_MODE_HS400ES
		.sup_mode = MSHC_MMC_MODE_HS200_1_8V,
		.sup_mode = MSHC_MMC_MODE_HS400_1_8V,
		.sup_mode = MSHC_MMC_MODE_HS400ES,
		.sup_mode = 0,
		.es_sup = 1,
		#endif
	    .hs200_tx_data = 0x60,
		.hs200_rx_cmd = 0x88,
		.hs200_rx_data = 0x8c,
	    .hs400_tx_data = 0x86,
		.hs400_rx_cmd = 0x6e,
		.hs400_rx_data = 0x3a,
	},
	{
		.mmc_name = "008GB0",
	},
	{
		.mmc_name = "032G32",
	},
	{
		.mmc_name = "AJTD4R",
	},
	{
		.mmc_name = "004GA0",
	},
	{
		.mmc_name = "008G30",
	},
	{
		.mmc_name = "08A391",
	},
	{
		.mmc_name = "SBS3S2",
	},

	{
		.mmc_name = "064G02",
	},

	{0},
};


void soc_mshc_ctrl_reset(void *p_rev)
{
	unsigned int cfg;
	unsigned int timeout = 0xffff;

	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL1, 3, 3);
	udelay(25);
	while (fh_pmu_get_reg(REG_EMMC_CLK_RST_CTRL1) & (3)) {
		timeout--;
		if (timeout == 0) {
			pr_err("mshc reset timeout !!!!!\n");
			return;
		}
	}

	fh_pmu_set_reg_m(REG_EMMC_CARD_PAD_SEL, 3 << 5, 7 << 5);
	fh_pmu_set_reg_m(REG_EMMC_CARD_PAD_SEL, 4 << 8, 7 << 8);
	fh_pmu_set_reg_m(REG_EMMC_CARD_PAD_SEL, 0, 1 << 4);
}

void soc_mshc_clk_set(void *p_rev, unsigned int clock)
{
	unsigned int emmc_clk[] = {
			24000000, 52000000, 200000000};
	unsigned int base_clk = 0, div;
	unsigned int i, cfg;

	if (clock > 200000000) {
		pr_err("not support clk %d; max is 200000000\n", clock);
		return;
	}

	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			0, 1 << 18);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL1,
			0, 1 << 4);

	if (clock == 200000000) {
		fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL1,
				(3 << 2), 0x0000000c);
		fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
				(1<<24), 0x7f000000);
		fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL1,
				0, 0x00001fc0);
		fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
				1 << 18, 1 << 18);

		fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL1,
				1 << 4, 1 << 4);
		return;
	}
	for (i = 0; i < ARRAY_SIZE(emmc_clk); i++) {
		if (clock <= emmc_clk[i]) {
			base_clk = emmc_clk[i];
			break;
		}
	}

	div = base_clk / clock;
	if (div == 0)
		pr_err("div can't be 0\n");

	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL1,
			(i << 2), 0x0000000c);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			((div-1)<<24), 0x7f000000);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			1 << 18, 1 << 18);
}

#define INIT_EMMC_CLK  400000
void soc_mshc_clk_init(void *p_rev)
{
	unsigned int cfg;

	soc_mshc_clk_set(p_rev, INIT_EMMC_CLK);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			0, 0x00fc0000);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			2 << 2, 3 << 2);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			1 << 4, 3 << 4);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			24 << 6, 0x1f << 6);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			1 << 11, 3 << 11);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			24 << 13, 0x1f << 13);
	fh_pmu_set_reg_m(REG_EMMC_CLK_RST_CTRL0,
			0x00cc0000, 0x00fc0000);
}

struct mshc_lite_plat_info mshc_plat = {
	.soc_clk_init = soc_mshc_clk_init,
	.soc_ctrl_reset = soc_mshc_ctrl_reset,
	.emmc_info_list = emmc_card_array,
	.clk_set = soc_mshc_clk_set,
};

static struct platform_device fh_mshc_device = {
	.name			= "fh_mshc",
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_mshc_resources),
	.resource		= fh_mshc_resources,
	.dev			= {
		.platform_data = &mshc_plat,
	},
};

static struct platform_device fh_uart0_device = {
	.name				= "ttyS",
	.id					= 0,
	.num_resources		= ARRAY_SIZE(fh_uart0_resources),
	.resource			= fh_uart0_resources,
	.dev.platform_data	= &fh_uart_platform_data[0],
};

static struct platform_device fh_uart1_device = {
	.name				= "ttyS",
	.id					= 1,
	.num_resources		= ARRAY_SIZE(fh_uart1_resources),
	.resource			= fh_uart1_resources,
	.dev.platform_data	= &fh_uart_platform_data[1],
};

static struct platform_device fh_uart2_device = {
	.name				= "ttyS",
	.id					= 2,
	.num_resources		= ARRAY_SIZE(fh_uart2_resources),
	.resource			= fh_uart2_resources,
	.dev.platform_data	= &fh_uart_platform_data[2],
};

static struct platform_device fh_uart3_device = {
	.name				= "ttyS",
	.id					= 3,
	.num_resources		= ARRAY_SIZE(fh_uart3_resources),
	.resource			= fh_uart3_resources,
	.dev.platform_data	= &fh_uart_platform_data[3],
};

static struct platform_device fh_uart4_device = {
	.name				= "ttyS",
	.id					= 4,
	.num_resources		= ARRAY_SIZE(fh_uart4_resources),
	.resource			= fh_uart4_resources,
	.dev.platform_data	= &fh_uart_platform_data[4],
};

static struct platform_device fh_uart5_device = {
	.name				= "ttyS",
	.id					= 5,
	.num_resources		= ARRAY_SIZE(fh_uart5_resources),
	.resource			= fh_uart5_resources,
	.dev.platform_data	= &fh_uart_platform_data[5],
};

static struct platform_device fh_hash_device = {
	.name				= "fh_hash",
	.num_resources		= ARRAY_SIZE(fh_mc_hash_resources),
	.resource			= fh_mc_hash_resources,
};


static struct platform_device fh_gpio0_device = {
	.name			= GPIO_NAME,
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_gpio0_resources),
	.resource		= fh_gpio0_resources,
	.dev			= {
		.platform_data = &fh_gpio0_chip,
	},
};

static struct platform_device fh_gpio1_device = {
	.name			= GPIO_NAME,
	.id				= 1,
	.num_resources	= ARRAY_SIZE(fh_gpio1_resources),
	.resource		= fh_gpio1_resources,
	.dev			= {
		.platform_data = &fh_gpio1_chip,
	},
};

static struct platform_device fh_gpio2_device = {
	.name			= GPIO_NAME,
	.id				= 2,
	.num_resources	= ARRAY_SIZE(fh_gpio2_resources),
	.resource		= fh_gpio2_resources,
	.dev			= {
		.platform_data = &fh_gpio2_chip,
	},
};

static struct platform_device fh_gpio3_device = {
	.name			= GPIO_NAME,
	.id				= 3,
	.num_resources	= ARRAY_SIZE(fh_gpio3_resources),
	.resource		= fh_gpio3_resources,
	.dev			= {
		.platform_data = &fh_gpio3_chip,
	},
};

static struct platform_device fh_gpio4_device = {
	.name			= GPIO_NAME,
	.id				= 4,
	.num_resources	= ARRAY_SIZE(fh_gpio4_resources),
	.resource		= fh_gpio4_resources,
	.dev			= {
		.platform_data = &fh_gpio4_chip,
	},
};



static struct resource fh_mc_dma_resources[] = {
{
	.start          = (DMA0_REG_BASE),
	.end            = (DMA0_REG_BASE) + SZ_16K - 1,
	.flags          = IORESOURCE_MEM,
},
{
	.start          = DMA0_IRQ,
	.end            = DMA0_IRQ,
	.flags          = IORESOURCE_IRQ,
},
};

struct fh_mc_dma_platform_data mc_dma_plat_data = {
.chan_priority  = CHAN_PRIORITY_ASCENDING,
.clk_name       = "ahb_clk",
};

static struct platform_device fh_mc_dma_device = {
.name = "fh_mc_dmac",
.id = 0,
.num_resources = ARRAY_SIZE(fh_mc_dma_resources),
.resource = fh_mc_dma_resources,
.dev = {
	.platform_data = &mc_dma_plat_data,
	},
};


static struct resource fh_i2s_resources[] = {
	{
		.start		= I2S_REG_BASE,
		.end		= I2S_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= I2S0_IRQ,
		.end		= I2S0_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct fh_i2s_platform_data fh_i2s_data = {
	.dma_capture_channel = 4,
	.dma_playback_channel = 5,
	.dma_master = 0,
	.dma_rx_hs_num = 24,
	.dma_tx_hs_num = 25,
	.clk = "i2s_clk",
};

static struct platform_device fh_i2s_device = {
	.name			= "fh_audio",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_i2s_resources),
	.resource		= fh_i2s_resources,
	.dev			= {
		.platform_data = &fh_i2s_data,
	},
};

static struct platform_device fh_pinctrl_device = {
	.name			= "fh_pinctrl",
	.id			= 0,
};

static struct platform_device fh_i2c0_device = {
	.name			= "fh_i2c",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_i2c_resources_0),
	.resource		= fh_i2c_resources_0,
};

static struct platform_device fh_i2c1_device = {
	.name			= "fh_i2c",
	.id			= 1,
	.num_resources		= ARRAY_SIZE(fh_i2c_resources_1),
	.resource		= fh_i2c_resources_1,
};

static struct platform_device fh_i2c2_device = {
	.name			= "fh_i2c",
	.id			= 2,
	.num_resources		= ARRAY_SIZE(fh_i2c_resources_2),
	.resource		= fh_i2c_resources_2,
};
static struct platform_device fh_i2c3_device = {
	.name                   = "fh_i2c",
	.id                     = 3,
	.num_resources          = ARRAY_SIZE(fh_i2c_resources_3),
	.resource               = fh_i2c_resources_3,
};
static struct platform_device fh_i2c4_device = {
	.name                   = "fh_i2c",
	.id                     = 4,
	.num_resources          = ARRAY_SIZE(fh_i2c_resources_4),
	.resource               = fh_i2c_resources_4,
};
static struct platform_device fh_i2c5_device = {
	.name                   = "fh_i2c",
	.id                     = 5,
	.num_resources          = ARRAY_SIZE(fh_i2c_resources_5),
	.resource               = fh_i2c_resources_5,
};

static struct fh_rtc_plat_data rtc_plat_data = {
	.lut_cof = 69,
	.lut_offset = 0xf7,
	.tsensor_cp_default_out = 0x9e3,
};

static struct platform_device fh_rtc_device = {
	.name			= "fh_rtc",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_rtc_resources),
	.resource		= fh_rtc_resources,
	.dev.platform_data	= &rtc_plat_data,
};

#ifdef CONFIG_HW_RANDOM_FH
static struct platform_device fh_rng_device = {
	.name			= "fh-rng",
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_rng_resources),
	.resource		= fh_rng_resources,
	.dev			= {
		.platform_data = NULL,
	}
};
#endif

static struct fh_usb_platform_data fh_usb0_data = {
	.dr_mode  = "host",
	.maximum_speed	= "high-speed",
	.vbus_pwren = 60, /* GPIO7_4 */
	.hcd_id = 0,
};

static struct fh_usb_platform_data fh_usb1_data = {
	.dr_mode  = "host",
	.maximum_speed	= "super-speed",
	.vbus_pwren = 63,  /* GPIO7_7 */
	.hcd_id = 1,
};

struct platform_device fh_usb0_device = {
	.name			= "dwc3",
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_usb0_resources),
	.resource		= fh_usb0_resources,
	.dev			= {
		.platform_data = &fh_usb0_data,
		.coherent_dma_mask = DMA_BIT_MASK(32),
	}
};

struct platform_device fh_usb1_device = {
	.name			= "dwc3",
	.id				= 1,
	.num_resources	= ARRAY_SIZE(fh_usb1_resources),
	.resource		= fh_usb1_resources,
	.dev			= {
		.platform_data = &fh_usb1_data,
		.coherent_dma_mask = DMA_BIT_MASK(32),
	}
};

static struct fh_pwm_data pwm_data = {
	.npwm = 12,
};

static struct platform_device fh_pwm_device = {
	.name			= "fh_pwm",
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_pwm_resources),
	.resource		= fh_pwm_resources,
	.dev			= {
		.platform_data = &pwm_data,
	},
};

struct platform_device fh_wdt0_device = {
	.name			= "fh_wdtv2",
	.id				= 0,
	.num_resources	= ARRAY_SIZE(fh_wdt0_resources),
	.resource		= fh_wdt0_resources,
	.dev			= {
		.platform_data = NULL,
	}
};

#ifdef CONFIG_FH_TSENSOR
struct platform_device fh_tsensor_device = {
	.name			= "fh_tsensor",
	.id				= 0,
};
#endif


#define FH_SFC_CS0	(103)
#define FH_SPI0_CS0	(90)
#define FH_SPI1_CS0	(107)

#define SFC_FIFO_DEPTH				(128)
#define SFC_CLK_IN					(200000000)
#define SFC_MAX_SLAVE_NO			(1)
#define SFC_DMA_RX_CHANNEL			(0)
#define SFC_DMA_TX_CHANNEL			(1)

#define SPI0_FIFO_DEPTH				(64)
#define SPI0_CLK_IN					(100000000)
#define SPI0_MAX_SLAVE_NO			(1)
#define SPI0_DMA_RX_CHANNEL			(2)
#define SPI0_DMA_TX_CHANNEL			(3)

#define SPI1_CLK_IN					(100000000)
#define SPI1_MAX_SLAVE_NO			(1)


/* SPI_TRANSFER_USE_DMA */
static struct fh_spi_platform_data fh_sfc_data = {
	.bus_no = 0,
	.apb_clock_in = SFC_CLK_IN,
	.clock_source = {SFC_CLK_IN},
	.clock_source_num = 1,
	.slave_max_num = SFC_MAX_SLAVE_NO,
	.cs_data[0].GPIO_Pin = FH_SFC_CS0,
	.cs_data[0].name = "sfc_cs0",
	.clk_name = "sfc_clk",
	.dma_transfer_enable = SPI_TRANSFER_USE_DMA,
	.rx_dma_channel = SFC_DMA_RX_CHANNEL,
	.rx_handshake_num = 32,
	/*dma use inc mode could move data by burst mode...*/
	/*or move data use single mode with low efficient*/
	.ctl_wire_support = ONE_WIRE_SUPPORT | DUAL_WIRE_SUPPORT |
	MULTI_WIRE_SUPPORT,
};

static struct fh_spi_platform_data fh_spi0_data = {
	.bus_no = 1,
	.apb_clock_in = SPI0_CLK_IN,
	.clock_source = {SPI0_CLK_IN},
	.clock_source_num = 1,
	.slave_max_num = SPI0_MAX_SLAVE_NO,
	.cs_data[0].GPIO_Pin = FH_SPI0_CS0,
	.cs_data[0].name = "spi0_cs1",
	.clk_name = "spi0_clk",
	.ctl_wire_support = 0,
};

static struct fh_spi_platform_data fh_spi1_data = {
	.bus_no = 2,
	.apb_clock_in = SPI1_CLK_IN,
	.clock_source = {SPI1_CLK_IN},
	.clock_source_num = 1,
	.slave_max_num = SPI1_MAX_SLAVE_NO,
	.cs_data[0].GPIO_Pin = FH_SPI1_CS0,
	.cs_data[0].name = "spi1_cs0",
	.clk_name = "spi1_clk",
	.ctl_wire_support = 0,
};

static struct platform_device fh_sfc_device = {
	.name			= "fh_spi",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_sfc_resources),
	.resource		= fh_sfc_resources,
	.dev			= {
		.platform_data = &fh_sfc_data,
	},
};

static struct platform_device fh_spi0_device = {
	.name			= "fh_spi",
	.id			= 1,
	.num_resources		= ARRAY_SIZE(fh_spi0_resources),
	.resource		= fh_spi0_resources,
	.dev			= {
		.platform_data = &fh_spi0_data,
	},
};

static struct platform_device fh_spi1_device = {
	.name			= "fh_spi",
	.id			= 2,
	.num_resources		= ARRAY_SIZE(fh_spi1_resources),
	.resource		= fh_spi1_resources,
	.dev			= {
		.platform_data = &fh_spi1_data,
	},
};

#ifdef CONFIG_FH_RSA
static struct platform_device fh_rsa_device = {
	.name			= "fh_rsa",
	.id				= 1,
	.num_resources	= ARRAY_SIZE(fh_rsa_resources),
	.resource		= fh_rsa_resources,
	.dev			= {
		.platform_data = NULL,
	},
};
#endif

static struct mtd_partition fh_sf_parts[] = {
	{
		/* head & Ramboot */
		.name		= "bootstrap",
		.offset		= 0,
		.size		= SZ_128K,
		.mask_flags	= MTD_WRITEABLE, /* force read-only */
	}, {
		/* Ramboot & U-Boot environment */
		.name		= "uboot-env",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_128K,
		.mask_flags	= MTD_WRITEABLE, /* force read-only */
	}, {
		/* U-Boot */
		.name		= "uboot",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_512K,
		.mask_flags	= MTD_WRITEABLE, /* force read-only */
	}, {
		.name		= "kernel",
		.offset		= MTDPART_OFS_APPEND,
		.size		= 3*SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "rootfs",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_8M,
		.mask_flags	= 0,
	}, {
		.name		= "app",
		.offset		= MTDPART_OFS_APPEND,
		.size		= MTDPART_SIZ_FULL,
		.mask_flags	= 0,
	}
	/* mtdparts=
	* spi_flash:256k(bootstrap),
	* 64k(u-boot-env),
	* 192k(u-boot),4M(kernel),
	* 8M(rootfs),
	* -(app) */
	/* two blocks with bad block table (and mirror) at the end */
};

#ifdef CONFIG_MTD_SPI_NAND
static struct mtd_partition fh_sf_nand_parts[] = {
	{
		/* head & Ramboot */
		.name		= "bootstrap",
		.offset		= 0,
		.size		= SZ_128K,
		.mask_flags	= MTD_WRITEABLE, /* force read-only */
	}, {
		.name		= "uboot-env",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_128K,
		.mask_flags	= MTD_WRITEABLE,
	}, {
		.name		= "uboot",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_512K,
		.mask_flags	= MTD_WRITEABLE,
	}, {
		.name		= "kernel",
		.offset		= MTDPART_OFS_APPEND,
		.size		= 3*SZ_1M,
		.mask_flags	= 0,
	}, {
		.name		= "rootfs",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_8M,
		.mask_flags	= 0,
	}, {
		.name		= "app",
		.offset		= MTDPART_OFS_APPEND,
		.size		= MTDPART_SIZ_FULL,
		.mask_flags	= 0,
	}
	/* mtdparts=
	 * spi0.0:64k(bootstrap),
	 * 64k(u-boot-env),
	 * 192k(u-boot),
	 * 4M(kernel),
	 * 8M(rootfs),
	 * -(app)
	 * two blocks with bad block table (and mirror) at the end
	 */
};
#endif

static struct flash_platform_data fh_flash_platform_data  = {
	.name		= "spi_flash",
	.parts		= fh_sf_parts,
	.nr_parts	= ARRAY_SIZE(fh_sf_parts),
};

#ifdef CONFIG_MTD_SPI_NAND
static struct flash_platform_data fh_nandflash_platform_data  = {
	.name		= "spi_nandflash",
	.parts		= fh_sf_nand_parts,
	.nr_parts	= ARRAY_SIZE(fh_sf_nand_parts),
};
#endif

static struct spi_board_info fh_spi_devices[] = {
#ifdef CONFIG_MTD_SPI_NAND
	{
		.modalias		= "spi-nand",
		.bus_num		= 0,
		.chip_select	= 0,
		.max_speed_hz	= 50000000,
		.mode			= SPI_MODE_3,
		.platform_data	 = &fh_nandflash_platform_data,
	},
#endif
	{
		.modalias        = "m25p80",
		.bus_num         = 0,
		.chip_select     = 0,
		/* multi wire should adapt spi para 'ctl_wire_support'*/
		.mode            = SPI_MODE_3  | SPI_RX_DUAL,
		.max_speed_hz    = 50000000,
		.platform_data   = &fh_flash_platform_data,
	},
};

#ifdef CONFIG_MOL_PERF
static struct resource fh_mc_perf_resources[] = {
	{
		.start		= PERF_MON0_REG_BASE,
		.end		= PERF_MON0_REG_BASE + SZ_4K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= DMC_PERF_MON_IRQ,
		.end		= DMC_PERF_MON_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct platform_device fh_mc_perf_device = {
	.name				= "fh-mc-perfmon",
	.id					= 0,
	.num_resources		= ARRAY_SIZE(fh_mc_perf_resources),
	.resource			= fh_mc_perf_resources,
	.dev = {
		.platform_data = (void *)6, /* channel num */
	}
};
#endif


static struct resource mol_efuse_resources[] = {
	{
		.start = EFUSE_REG_BASE,
		.end = EFUSE_REG_BASE + SZ_16K - 1,
		.flags = IORESOURCE_MEM,
	},
};

#ifdef CONFIG_MOL_EFUSE_TEE
static int efuse_uuid[11] = {0x796ad1ff, 0x5565, 0x4141,
		0x9a, 0x1c, 0x29, 0x00, 0x20, 0xaa, 0x9f, 0x16};
#endif

struct mol_efuse_platform_data mol_efuse_plat_data = {
	.efuse_support_flag = CRYPTO_CPU_SET_KEY |
	CRYPTO_EX_MEM_SET_KEY | CRYPTO_EX_MEM_SWITCH_KEY |
	CRYPTO_EX_MEM_4_ENTRY_1_KEY | CRYPTO_EX_MEM_INDEP_POWER,
#ifdef CONFIG_MOL_EFUSE_TEE
	.optee_uuid = efuse_uuid,
#endif
};


static struct platform_device mol_efuse_device = {
	.name = "fh_efuse",
	.id = 0,
	.num_resources = ARRAY_SIZE(mol_efuse_resources),
	.resource = mol_efuse_resources,
	.dev = {
		.platform_data = &mol_efuse_plat_data,
	},
};


static struct resource fh_cesa_resources[] = {
	{
		.start		= AES_REG_BASE,
		.end		= AES_REG_BASE + SZ_16K - 1,
		.flags		= IORESOURCE_MEM,
	},
	{
		.start		= AES_IRQ,
		.end		= AES_IRQ,
		.flags		= IORESOURCE_IRQ,
	},
};

#ifdef CONFIG_CRYPTO_DEV_FH_AES_TEE
static int aes_uuid[11] = {0xdd00d7bd, 0xe9e3, 0x4dcb,
		0xad, 0xbc, 0xda, 0x54, 0xa7, 0x1b, 0x9b, 0x65};
#endif

static struct platform_device fh_cesa_device = {
	.name			= "fh_cesa",
	.id			= 0,
	.num_resources		= ARRAY_SIZE(fh_cesa_resources),
	.resource		= fh_cesa_resources,
	.dev			= {
#ifdef CONFIG_CRYPTO_DEV_FH_AES_TEE
	.platform_data = aes_uuid,
#else
	.platform_data = NULL,
#endif
	},
};

static struct platform_device *fh8898_devices[] __initdata = {
	&fh_uart0_device,
	&fh_uart1_device,
	&fh_uart2_device,
	&fh_uart3_device,
	&fh_uart4_device,
	&fh_uart5_device,
	&fh_pinctrl_device,
	//eth0 means mac1
	&fh_gmac_qos_1_device,
	//eth1 means mac0
	&fh_gmac_qos_0_device,
	&fh_gpio0_device,
	&fh_gpio1_device,
	&fh_gpio2_device,
	&fh_gpio3_device,
	&fh_gpio4_device,
	&fh_i2c0_device,
	&fh_i2c1_device,
	&fh_i2c2_device,
	&fh_i2c3_device,
	&fh_i2c4_device,
	&fh_i2c5_device,
	&fh_rtc_device,
#ifdef CONFIG_HW_RANDOM_FH
	&fh_rng_device,
#endif
	&fh_sd0_device,
	&fh_sd1_device,
	&fh_mshc_device,
	&fh_mc_dma_device,
	&fh_sadc_device,
	&fh_cesa_device,
	&mol_efuse_device,
	&fh_sfc_device,
	&fh_spi0_device,
	&fh_spi1_device,
	&fh_i2s_device,
	&fh_pwm_device,
	&fh_wdt0_device,
#ifdef CONFIG_USB_DWC3_HCD1_ENABLE
	&fh_usb0_device,
#endif
#ifdef CONFIG_USB_DWC3_HCD2_ENABLE
	&fh_usb1_device,
#endif
#ifdef CONFIG_FH_TSENSOR
	&fh_tsensor_device,
#endif
#ifdef CONFIG_MOL_PERF
	&fh_mc_perf_device,
#endif
#ifdef CONFIG_FH_RSA
	&fh_rsa_device,
#endif
#ifdef CONFIG_MOL_HASH
	&fh_hash_device,
#endif
};

extern void early_print(const char *str, ...);

static void __init fh_console_pre_init(struct fh_platform_uart *plat, int num)
{
	int idx = 0;

	for (; idx < num; idx++) {
		struct uart_port *port;

		port            = &fh_serial_ports[idx];
		port->mapbase   = plat[idx].mapbase;
		port->fifosize  = plat[idx].fifo_size;
		port->uartclk   = plat[idx].uartclk;

		switch (idx) {
		case 0:
			port->membase = (unsigned char *)VA_UART0_REG_BASE;
			break;
		case 1:
			port->membase = (unsigned char *)VA_UART1_REG_BASE;
			break;
		case 2:
			port->membase = (unsigned char *)VA_UART2_REG_BASE;
			break;
		case 3:
			port->membase = (unsigned char *)VA_UART3_REG_BASE;
			break;
		case 4:
			port->membase = (unsigned char *)VA_UART4_REG_BASE;
			break;
		case 5:
			port->membase = (unsigned char *)VA_UART5_REG_BASE;
			break;
		default:
			break;
		}
	}
}

static void __init fh8898_map_io(void)
{
	iotable_init(fh8898_io_desc, ARRAY_SIZE(fh8898_io_desc));
	/* enable 33bit address space */
	fh_pmu_set_reg(REG_CPU_ADDR_MSB_SEL, 0xc);

	fh_console_pre_init(fh_uart_platform_data,
			ARRAY_SIZE(fh_uart_platform_data));
}


static __init void fh8898_board_init(void)
{
	platform_add_devices(fh8898_devices,
			ARRAY_SIZE(fh8898_devices));
	spi_register_board_info(fh_spi_devices, ARRAY_SIZE(fh_spi_devices));
}
void  __init fh_timer_init_no_of(unsigned int iovbase,
	unsigned int irqno);

static void __init fh8898_init_early(void)
{
	fh_pmu_init();
	/* Configure DMA */
	fh_pmu_set_dma_sel_low(0);
	fh_pmu_set_dma_sel_high(0);
	fh_pmu_set_dma0_axcache(0);
	fh_pmu_set_dma1_axcache(0);
	mol_pmu_set_efuse_lock_blk(1 << 24);
#ifdef CONFIG_SPI_FH_SLAVE
	fh_pmu_spi_slave_enable(1);
#else
	fh_pmu_spi_slave_enable(0);
#endif
	fh_pinctrl_init(VA_CEN_PIN_REG_BASE + 0x4);

	fh_pmu_set_reg(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x178,
	0x00108a01);
	fh_pmu_set_reg(SYS_REG_P2V_OFF(VDU_SYS_APB_REG_BASE) + 0x17c,
	0x001fffff);
	fh_pmu_set_reg_m(SYS_REG_P2V_OFF(VDU_SYS_PIN_REG_BASE) + 0x90,
	4 << 16, 7 << 16);
}

static void fh8898_restart
				(enum reboot_mode mode, const char *cmd)
{
	fh_pmu_restart();
}
static void __init fh_gic_no_of_init(void)
{
	void *p_gicd = ioremap(GICD_REG_BASE, SZ_16K);
	void *p_gicc = ioremap(GICC_REG_BASE, SZ_16K);

	gic_init(0, -1, p_gicd, p_gicc);
}

int  arch_timer_noof_init(u32 freq,
	u32 ppilist[4], int alwayson, int suspendstop);
static void  __init init_arch_timer_noof(void)
{
	/* arm cortexa7 standard arch-timer ppi id */
	u32 ppilist[4] = {13+16, 14+16, 11+16, 10+16};
	struct clk *cpu_clk;
	unsigned long rate;

	/* arch timer enable */
	fh_pmu_set_reg_m(REG_CPU_CORE_CTRL, BIT(3), BIT(3));
	fh_clk_init();

	cpu_clk = clk_get(NULL, "cpu_clk");
	if (IS_ERR(cpu_clk)) {
		pr_err("get cpu_clk err: %ld\n", PTR_ERR(cpu_clk));
		return;
	}
	rate = clk_get_rate(cpu_clk);
	arch_timer_noof_init(rate, ppilist, 0, 0);
}


MACHINE_START(FH8898, "FH8898")
	.atag_offset	= 0x100,
	.map_io		= fh8898_map_io,
	.init_irq	= fh_gic_no_of_init,
	.init_time	= init_arch_timer_noof,
	.init_machine	= fh8898_board_init,
	.init_early	= fh8898_init_early,
	.restart	= fh8898_restart,
#ifdef CONFIG_SMP
	.smp_init = fh_smp_init,
#endif
MACHINE_END



